from chatbot import settings
from chatbot.component.singleton import singleton
from chatbot.const import const


@singleton
class BotFactory(object):
    def __init__(self):
        self.bots = {}

    def init(self):
        from chatbot.models import Tenant
        from chatbot.bot.engine import ChatBot
        tenants_from_db = Tenant.objects.all()

        for tenant in tenants_from_db:
            tenant_id = tenant.id

            tokenizer = self.load_tokenizer(tenant_id)

            logic_adapters, preprocessors = self.load_skill(tenant_id)
            scripts = self.load_scripts(tenant_id)
            basic_configurations = self.load_basic_configuration(tenant_id)

            channels = self.load_channels(tenant_id)

            for channel in channels:
                channel_id = channel.id
                bot = ChatBot(**settings.CHAT_BOT_SETTING,
                              logic_adapters=logic_adapters,
                              preprocessors=preprocessors,
                              scripts=scripts,
                              configurations=basic_configurations,
                              channel=channel,
                              read_only=True,
                              tenant=tenant,
                              tokenizer=tokenizer)
                self.bots[channel_id] = bot

    @staticmethod
    def load_scripts(tenant_id):
        from chatbot.models import ScriptConfiguration, Script
        script_configurations = ScriptConfiguration.objects.filter(tenant_id=tenant_id)
        fixed_scripts = {}
        for conf in script_configurations:
            scripts = Script.objects.filter(configuration=conf.id)
            script_list = []
            for script in scripts:
                script_list.append(script.script)
            fixed_scripts[conf.code] = script_list

        return fixed_scripts

    @staticmethod
    def load_skill(tenant_id):
        from chatbot.models import SkillConfiguration
        skills = SkillConfiguration.objects.filter(tenant_id=tenant_id).filter(state=True)
        logic_adapters = []
        preprocessors = []
        for skill in skills:
            adapter = {
                'import_path': skill.path,
                'name': skill.code
            }
            if skill.skill_type == const.SKILL_TYPE_LOGIC_ADAPTER:
                logic_adapters.append(adapter)
            else:
                preprocessors.append(adapter)

        return logic_adapters, preprocessors

    @staticmethod
    def load_tokenizer(tenant_id):
        from chatbot.bot.domain.word import Word

        word = Word(tenant_id)
        word.loading_user_dict()
        return word

    @staticmethod
    def load_basic_configuration(tenant_id):
        from chatbot.models import BasicConfiguration

        basic_configurations = BasicConfiguration.objects.filter(tenant_id=tenant_id)
        configurations = {}
        for conf in basic_configurations:
            configurations[conf.code] = conf.value
        return configurations

    @staticmethod
    def load_channels(tenant_id):
        from chatbot.models import Channel

        return Channel.objects.filter(tenant_id=tenant_id).filter(state=const.STATE_ACTIVE)

    def get_bot(self, channel_id: int):
        return self.bots.get(channel_id)
